package com.liujun.io.nio.trans.tran;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Semaphore;

import com.liujun.io.nio.trans.util.IOutils;
import com.liujun.io.nio.trans.util.PropertiesUtils;

/**
 * 前端的数据向后端传输通道
* 源文件名：TransProxyFile.java
* 文件版本：1.0.0
* 创建作者：liujun
* 创建日期：2016年8月24日
* 修改作者：liujun
* 修改日期：2016年8月24日
* 文件描述：liujun
* 版权所有：Copyright 2016 zjhz, Inc. All Rights Reserved.
*/
public class TransProxyFile implements TransProxyInf {

    /**
     * 生成文件的路径信息
     * 
     * @字段说明 url
     */
    private String url;

    /**
     * 文件信息
     */
    private File fileInfo;

    /**
     * 文件大小,2M
     */
    private static final int FILE_SIZE = 1024 * 1024;

    /**
     * 随机文件读取流程
     * 
     * @字段说明 randomFile
     */
    private RandomAccessFile randomFile = null;

    /**
     * 许可信号量
     */
    private Semaphore semp = new Semaphore(1);

    /**
     * 通道信息
     * 
     * @字段说明 channel
     */
    private FileChannel channel = null;

    /**
     * 文件时间
     * 
     * @字段说明 fileTime
     */
    private long fileTime;

    public TransProxyFile() {
        this.openFile();
    }

    /**
     * 将网络通道转换为file 方法描述
     * 
     * @param socketChanel
     * @创建日期 2016年8月11日
     */
    public boolean tranFrom(SocketChannel socketChanel) throws IOException {
        if (channel.isOpen()) {
            boolean accquicr = false;
            try {
                // 试图去拿到许可执行
                accquicr = semp.tryAcquire();

                if (accquicr) {
                    long tranFrom = 0;
                    long writeSize = 0;

                    if (socketChanel.isOpen()) {
                        // 读取源通道,将通道中的数据，将文件写满
                        if ((tranFrom = channel.transferFrom(socketChanel, writeSize, FILE_SIZE)) > 0) {
                            writeSize = writeSize + tranFrom;
                        }
                    }

                    if (writeSize > 0) {
                        // 标识数据已经转换到通道中
                        return true;
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
                throw e;
            } finally {
                if (accquicr) {
                    // 释放许可
                    semp.release();
                }
            }
        }
        return false;
    }

    /**
     * 将数据写入后端通道信息 方法描述
     * 
     * @param toChannel
     * @创建日期 2016年8月11日
     */
    public boolean tranTo(SocketChannel toChannel) throws IOException {
        if (channel.isOpen()) {
            boolean accquicr = false;
            try {
                // 试图去拿到许可执行
                accquicr = semp.tryAcquire();

                if (accquicr) {

                    long writeSize = 0;
                    long writePostionTmp = 0;

                    // 进行目标通道的写入
                    while ((writeSize = channel.transferTo(writePostionTmp, FILE_SIZE - writePostionTmp,
                            toChannel)) > 0) {
                        // 设置文件的大小信息
                        writePostionTmp = writePostionTmp + writeSize;
                    }

                    // 进行文件清空
                    channel.position(0);
                    channel.truncate(0);
                }

            } catch (IOException e) {
                e.printStackTrace();
                throw e;
            } finally {
                if (accquicr) {
                    semp.release();
                }

            }
        }

        return true;

    }

    /**
     * 进行文件流通道的打开操作 方法描述
     * 
     * @创建日期 2016年8月15日
     */
    public void openFile() {
        try {
            // 系统时间纳秒数，以保证文件不重复
            fileTime = System.nanoTime();
            url = PropertiesUtils.getInstance().getValue("classPath") + "/" + fileTime;
            fileInfo = new File(url);
            randomFile = new RandomAccessFile(fileInfo.getAbsolutePath(), "rw");

            channel = randomFile.getChannel();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 重置连接信息 方法描述
     * 
     * @创建日期 2016年8月19日
     */
    public void reset() {
        // 写入完成后清空文件通道信息
        FileLock lock = null;
        try {
            lock = channel.tryLock();
            // 进行文件清空
            channel.truncate(0);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                lock.release();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭流信息 方法描述
     * 
     * @创建日期 2016年8月13日
     */
    public void close() {

        // 写入完成后清空文件通道信息
        FileLock lock = null;
        try {
            lock = channel.tryLock();

            // 进行文件清空
            channel.truncate(0);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                lock.release();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        IOutils.closeStream(channel);
        IOutils.closeStream(randomFile);
    }

}
